/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "物体节点.h"

#include <物体/物体.h>

#include <Context/当前默认操作数据.h>
#include <Context/节点数据操作.h>
#include "Context/数据创建销毁.h"
#include "节点编辑.h"

#include "节点/插座/list/list物体插座.h"
#include "节点/插座/list/list数值插座.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/材质纹理插座.h"
#include "节点/socket_utils.h"



#include <mutex>



static S_物体* f_递归构建骨骼网格体(S_物体* 物体, S_设备环境& ctx) {
	S_物体* ob = nullptr;

	if (物体->m_Type == E_物体类型::t_骨骼) {
		f_ob_create骨骼虚拟体网格(ctx, 物体, nullptr);
		f_node_将现有物体包装成骨骼网格(ctx, 物体, nullptr);
		return 物体;
	}

	for (auto& e : 物体->m_子物体) {
		ob = f_递归构建骨骼网格体(e, ctx);
		if (ob) return ob;
	}

	return nullptr;
}




static void f_骨骼物体构建骨节物体(S_物体* 骨节, const S_物体* 骨骼) {
	for (auto& e : 骨骼->m_子物体) {
		S_物体* 骨节物体 = ((S_物体*)e->m_UserData);

		骨节物体->m_实例ID = e->m_实例ID + 1;
		骨节物体->m_UserData = (void*)e;
		f_ob_add子物体(骨节, 骨节物体);

		if (e->m_子物体.size()) {
			f_骨骼物体构建骨节物体(骨节, e);
		}
	}
}

static S_物体* f_递归更新骨节(S_物体* 骨骼, uint32& depth) {
	S_物体* ob = nullptr;

	if (骨骼->m_Type == E_物体类型::t_骨骼) {
		//vec3 size = 骨骼->f_get缩放() * vec3 { 0, 0, 1 };
		骨骼->m_实例ID = depth;
		++depth;

		
		uint32 num = 骨骼->m_子物体.size();
		if (num) {
			for (uint32 i = 0; i < num; ++i) {
				ob = f_递归更新骨节(骨骼->m_子物体[i], depth);
			}
		}
	}

	return nullptr;
}


/*static void f_更新骨节(S_物体* 骨骼, S_物体* 骨节, S_设备环境& ctx) {
	骨节->f_set位置(骨骼->f_get位置(), 0);
	骨节->f_set缩放(骨骼->f_get缩放(), 0);
	
	uint32 depth = 0;
	骨节->m_实例ID = depth;

	f_递归更新骨节(骨骼, 骨节->m_子物体.data(), depth);
}*/



static void f_从骨节更新编辑骨骼(S_物体* 根骨骼, S_物体** 骨干, S_物体** 骨节, uint32 depth, float32* 骨骼长度, const vec4& 父骨骼旋转, const float32 父骨骼长度) {
	//vec3 s = 骨节[骨骼->m_实例ID]->m_变换.location;
	uint32 num = 根骨骼->m_子物体.size();
	float32 最大长度 = 0.1;
	float32 骨节大小 = 0.1;


	S_骨骼* 骨骼 = f_ob_get骨骼数据(根骨骼);
	
	
	for (uint32 i = 0; i < num; ++i) {
		S_物体* 末端骨骼 = 根骨骼->m_子物体[i];

		S_骨骼* 骨骼数据 = f_ob_get骨骼数据(末端骨骼);

		vec3 e = 末端骨骼->m_变换.location + DEF_骨骼朝向;
		float32 两骨节距离 = 0;


		vec4 newQuat = 父骨骼旋转;
		if (depth) {
			vec3 s = 根骨骼->m_变换.location;
			vec3 骨骼方向 = e - s;


			两骨节距离 = vec_normalize(&骨骼方向);
			骨骼长度[末端骨骼->m_实例ID] = 两骨节距离;

			最大长度 = DEF_Max(根骨骼->m_变换.scale.x, 两骨节距离);
			最大长度 = 两骨节距离;
			//根骨骼->f_set缩放({ 最大长度, 最大长度, 最大长度 }, 0);
			骨骼数据->m_长度 = 两骨节距离;


			骨骼方向 = f_graph_quat变换坐标(f_graph_quat反向(父骨骼旋转), 骨骼方向);
			vec4 q = f_graph_quat两向量(骨骼方向, DEF_骨骼朝向);
			vec3 rot = f_graph_四元数转欧拉角(q);

			rot = vec3{ -rot.x, -rot.y, rot.z };
			骨干[末端骨骼->m_实例ID]->f_set旋转(rot, 0);
			//骨干[末端骨骼->m_实例ID]->f_set位置({ 0, 0, 父骨骼长度 }, 0);

			骨干[末端骨骼->m_实例ID]->f_set位置(s, 0);
			骨干[末端骨骼->m_实例ID]->f_set缩放({ 1, 1 ,1 }, 0);


			骨节大小 = DEF_Min(vec_len(骨骼方向), 骨节大小);


			vec4 newQuat = f_graph_quatNormalize(f_graph_quat相乘(q, 父骨骼旋转));
		}
		else {
			骨干[末端骨骼->m_实例ID]->m_变换.location = 末端骨骼->m_变换.location + DEF_骨骼朝向;
			骨节[末端骨骼->m_实例ID]->m_变换.location = 末端骨骼->m_变换.location + DEF_骨骼朝向;
		}
		

		f_从骨节更新编辑骨骼(末端骨骼, 骨干, 骨节, depth + 1, 骨骼长度, newQuat, 两骨节距离);
	}

	
	骨节[根骨骼->m_实例ID]->f_set缩放(vec3{ 骨节大小, 骨节大小, 骨节大小 }, 0);


	if (depth) {
		
	}
	else {
		//骨节[根骨骼->m_实例ID]->f_set缩放(vec3{ 骨节大小, 骨节大小, 骨节大小 }, 0);
	}


	if (根骨骼) {
		
	}
	else {

	}
}


static void f_将超出长度范围的骨节移动到范围内(S_物体* 根骨骼, S_物体** 骨节, uint32 depth, const float32* 骨骼长度, const vec3 移动修正) {
	uint32 num = 根骨骼->m_子物体.size();
	for (uint32 i = 0; i < num; ++i) {
		S_物体* 骨骼 = 根骨骼->m_子物体[i];
		S_物体* 当前开始骨节;

		vec3 e = f_从骨头取末端骨节(骨骼)->m_变换.location;
		if (depth) {
			当前开始骨节 = f_从骨头取前端骨节(骨骼);
		}
		else {
			//s = 骨节[0]->m_变换.location;
			当前开始骨节 = 骨节[0];
		}
		vec3 s = 当前开始骨节->m_变换.location;
		vec3 骨骼方向 = e - s;
		float32 两骨节距离 = vec_normalize(&骨骼方向);

		if (两骨节距离 > 骨骼长度[骨骼->m_实例ID] || 两骨节距离 < 骨骼长度[骨骼->m_实例ID]) {
			vec_mul(&骨骼方向, 两骨节距离 - 骨骼长度[骨骼->m_实例ID]);
			vec_sub(&(f_从骨头取末端骨节(骨骼)->m_变换.location), 骨骼方向);
			f_从骨头取末端骨节(骨骼)->m_isUpdate = true;
		}
		else {
			骨骼方向 = {};
		}

		f_将超出长度范围的骨节移动到范围内(骨骼, 骨节, depth + 1, 骨骼长度, 移动修正 + 骨骼方向);
	}
}


C_物体节点::C_物体节点(S_设备环境& ctx) : C_节点基类("物体节点") {
	m_Name = L"物体节点";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建UI32插座_I(L"数量");
	DEF_创建物体_1D插座_O(L"对象");

	m_物体类型 = f_prop_创建物体类型属性数据();
	m_物体类型.m_私有 = true;
}

C_物体节点::~C_物体节点() {
	
}

bool C_物体节点::f_update() {
	uint32 num = DEF_UI32插座数据(f_get输入插座(1));
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);

	for (uint32 i = 0; i < objs->count; ++i) {
		S_节点数据::m_全局物体set.erase(objs->ptr_userData[i]);
	}
	//for (auto& e : objs) {
	//	S_节点数据::m_全局物体set.erase(e);
	//}
	//f_创建网格物体组(objs, num, m_Ctx);
	uint32 已有数量 = objs->count;

	for (uint32 i = num; i < 已有数量; ++i) {
		f_NodeCtx_get默认场景()->f_remove物体(objs->ptr_userData[i], E_场景物体容器类型::e_集合);
		f_ob_销毁物体(objs->ptr_userData[i]);
	}
	f_core_array_resize((S_Array*)objs, num);

	for (uint32 i = 已有数量; i < objs->count; ++i) {
		objs->ptr_userData[i] = f_ob_创建物体(m_Ctx, E_物体类型::t_空);
	}

	for (uint32 i = 0; i < objs->count; ++i) {
		S_节点数据::m_全局物体set.insert(objs->ptr_userData[i]);
		f_NodeCtx_get默认场景()->f_add物体({objs->ptr_userData[i]}, E_场景物体容器类型::e_集合);
	}
	//for (auto& e : objs) {
	//	S_节点数据::m_全局物体set.insert(e);
	//}
	//f_NodeCtx_get默认场景()->f_add物体(objs, E_场景物体容器类型::e_集合);
	return false;
}

S_动画曲线组* C_物体节点::f_getAN曲线() {

	return nullptr;
}

void C_物体节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);

	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_ob_Load多物体(objs, f, m_Ctx);
}

void C_物体节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);

	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_ob_Save多物体(objs, f);
}

C_节点基类* f_node_创建物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体节点(ctx);
}

C_节点基类* f_node_加载物体节点(S_设备环境& ctx, FILE* f) {
	C_物体节点* node = new C_物体节点(ctx);

	return node;
}

void f_node_保存物体节点(C_节点基类* n, FILE* f) {
	C_物体节点* node = dynamic_cast<C_物体节点*>(n);
}




C_引用物体节点::C_引用物体节点(S_设备环境& ctx) : C_节点基类(DEF_引用物体节点, E_节点类型::e_节点Type_物体) {
	m_Name = L"引用物体";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_O(L"物体");

}

C_引用物体节点::~C_引用物体节点() {
}

bool C_引用物体节点::f_update() {
	auto* ob = DEF_物体插座数据(f_get输出插座(1), 0);
	if (ob) {
		m_name = ob->m_Name;
	}
	else {
		ob = f_node_从全局物体容器查找物体(m_name);
		f_get输出插座(1)->f_setData(ob);
	}
	return false;
}

S_动画曲线组* C_引用物体节点::f_getAN曲线() {
	return nullptr;
}

void C_引用物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	m_name = f_file_读取字符串(f);
}

void C_引用物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto* ob = DEF_物体插座数据(f_get输出插座(1), 0);
	if (ob) {
		m_name = ob->m_Name;
	}
	f_file_保存字符串(f, m_name);
}

C_节点基类* f_node_创建引用物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_引用物体节点(ctx);
}

C_节点基类* f_node_加载引用物体节点(S_设备环境& ctx, FILE* f) {
	C_引用物体节点* node = new C_引用物体节点(ctx);
	return node;
}

void f_node_保存引用物体节点(C_节点基类* n, FILE* f) {
	C_引用物体节点* node = dynamic_cast<C_引用物体节点*>(n);
}




C_物体虚拟体节点::C_物体虚拟体节点(S_设备环境& ctx) : C_节点基类(DEF_物体虚拟体节点, E_节点类型::e_节点Type_虚拟体) {
	m_Name = L"虚拟体";
	m_Ctx = ctx;

	m_Ob = f_node_创建虚拟体网格物体(ctx, E_物体类型::t_虚拟体);
	f_NodeCtx_录物体类节点(this, m_Ob);
	m_Ob->m_变换.scale = {0.2,0.2,0.2};
	m_Ob->m_Name = L"虚拟体";
	f_node_物体加入全局容器中(m_Ob);

	m_动画曲线列表 = f_an_创建曲线层();

	C_插座基类* socket;
	DEF_创建F32插座_I(L"大小", nullptr);
	DEF_创建物体_1D插座_I(L"子物体");
	DEF_创建物体插座_O(L"物体");
	f_get输入插座(2)->f_set多输入();

	m_虚拟体网格类型 = f_alloc_EnumProp(nullptr, 
	{
		{L"立方体", "立体线框"}, 
		{L"球体", "球体"},
		//{L"摄像机", "摄像机"},
	}, 
	L"显示类型");
	m_虚拟体网格类型.m_私有 = true;
	f_prop_enum(m_虚拟体网格类型) = 0;


	//m_虚拟体网格大小 = f_alloc_Vec3Prop(nullptr, L"大小");
	//m_虚拟体网格大小.m_私有 = true;
	//f_prop_Vec3(m_虚拟体网格大小) = {0.2,0.2,0.2};
}

C_物体虚拟体节点::~C_物体虚拟体节点() {
	delete m_Ob;
}

bool C_物体虚拟体节点::f_update() {
	float32 size = DEF_F32插座数据(f_get输入插座(1));

	switch (f_prop_enum(m_虚拟体网格类型)) {
	case 0:
		f_node_设置立方体虚拟网格(m_Ob, { 1,1,1 });
		break;

	case 1:
		f_node_设置球体虚拟网格(m_Ob, { 1,1,1 });
		break;

	case 2:
		break;
	default:
		break;
	}

	f_get输出插座(1)->f_setData(m_Ob);
	return false;
}

S_动画曲线组* C_物体虚拟体节点::f_getAN曲线() {
	f_an_清除曲线通道(m_动画曲线列表);

	if (m_Ob->m_位置) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
	}
	if (m_Ob->m_旋转) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
	}
	if (m_Ob->m_缩放) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
	}
	return m_动画曲线列表;
}

S_物体* C_物体虚拟体节点::f_get虚拟体() {
	return m_Ob;
}

void C_物体虚拟体节点::f_入回收() {
	m_Ob->m_渲染 = false;
	f_node_移除虚拟体(m_Ob);
}

void C_物体虚拟体节点::f_回收() {
	m_Ob->m_渲染 = true;
	f_node_创建立方体虚拟体(m_Ob);
}

void C_物体虚拟体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_虚拟体网格类型, 下一次读取数据指针);
			下一次读取数据指针 = f_ob_Load物体(m_Ob, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_物体虚拟体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_虚拟体网格类型, 块);
	f_ob_Save物体(m_Ob, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体虚拟体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体虚拟体节点(ctx);
}

C_节点基类* f_node_加载物体虚拟体节点(S_设备环境& ctx, FILE* f) {
	C_物体虚拟体节点* node = new C_物体虚拟体节点(ctx);
	return node;
}

void f_node_保存物体虚拟体节点(C_节点基类* n, FILE* f) {
	C_物体虚拟体节点* node = dynamic_cast<C_物体虚拟体节点*>(n);
}





C_取物体节点::C_取物体节点(S_设备环境& ctx) : C_节点基类(DEF_取物体节点, E_节点类型::e_节点Type_物体) {
	m_Name = L"取物体";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Str插座_I(L"名称");
	DEF_创建物体插座_O(L"物体");


	m_过滤类型 = f_alloc_EnumProp(nullptr, {
	    {L"网格"}, 
		{L"平行光"}, 
		{L"点光源"},
		{L"区域光"},
		{L"聚光灯"},
		{L"摄像机"},
		{L"虚拟体"},
	}, L"类型");
	m_过滤类型.m_私有 = true;

	m_动画曲线列表 = f_an_创建曲线层();
}

C_取物体节点::~C_取物体节点() {
	f_prop_Release(m_过滤类型);
}

bool C_取物体节点::f_update() {
	auto* socket = f_get输入插座(1);

	/*if (socket->f_isLink()) {

	}
	else {
		E_物体类型 type;
		switch (f_prop_enum(m_过滤类型)) {
		case 0:
			type = E_物体类型::t_网格;
			break;
		default:
			break;
		}
		f_ob_以类型查找子物体()
	}*/

	return false;
}

S_动画曲线组* C_取物体节点::f_getAN曲线() {
	auto* m_Ob = DEF_物体插座数据(f_get输出插座(1), 0);

	f_an_清除曲线通道(m_动画曲线列表);
	if (m_Ob) {
		if (m_Ob->m_位置) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
		}
		if (m_Ob->m_旋转) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
		}
		if (m_Ob->m_缩放) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
		}
	}
	
	return m_动画曲线列表;
}

void C_取物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_过滤类型, f);
}

void C_取物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_过滤类型, f);
}

C_节点基类* f_node_创建取物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体节点(ctx);
}
C_节点基类* f_node_加载取物体节点(S_设备环境& ctx, FILE* f) {
	C_取物体节点* node = new C_取物体节点(ctx);
	return node;
}
void f_node_保存取物体节点(C_节点基类* n, FILE* f) {
	C_取物体节点* node = dynamic_cast<C_取物体节点*>(n);
}




C_查找子物体节点::C_查找子物体节点(S_设备环境 & ctx) : C_节点基类(DEF_查找子物体节点) {
	m_Name = L"查找子物体";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(L"父物体");
	DEF_创建Str插座_I(L"名称");
	DEF_创建物体插座_O(L"子物体");

	m_查找类型 = f_alloc_EnumProp(nullptr, {
		{L"网格"}, 
		{L"平行光"}, 
		{L"点光源"},
		{L"区域光"},
		{L"聚光灯"},
		{L"摄像机"},
		{L"虚拟体"},
		}, L"类型");
	m_查找类型.m_私有 = true;

	m_动画曲线列表 = f_an_创建曲线层();
}

C_查找子物体节点::~C_查找子物体节点() {
	f_prop_Release(m_查找类型);
}

bool C_查找子物体节点::f_update() {
	auto* 物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	E_物体类型 类型 = f_ob_以名称索引取类型(f_prop_enum(m_查找类型));
	if(物体) 物体 = f_ob_以类型查找子物体(物体, 类型);
	f_get输出插座(1)->f_setData(物体);
	return false;
}

S_动画曲线组* C_查找子物体节点::f_getAN曲线() {
	auto* m_Ob = DEF_物体插座数据(f_get输出插座(1), 0);

	f_an_清除曲线通道(m_动画曲线列表);
	if (m_Ob) {
		if (m_Ob->m_位置) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
		}
		if (m_Ob->m_旋转) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
		}
		if (m_Ob->m_缩放) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
		}
	}
	
	return m_动画曲线列表;
}

void C_查找子物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_查找类型, f);
}

void C_查找子物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_查找类型, f);
}

C_节点基类* f_node_创建查找子物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_查找子物体节点(ctx);
}

C_节点基类* f_node_加载查找子物体节点(S_设备环境& ctx, FILE* f) {
	C_查找子物体节点* node = new C_查找子物体节点(ctx);
	return node;
}

void f_node_保存查找子物体节点(C_节点基类* n, FILE* f) {
	C_查找子物体节点* node = dynamic_cast<C_查找子物体节点*>(n);
}




C_物体父子关系节点::C_物体父子关系节点(S_设备环境& ctx) : C_节点基类("物体父子关系节点") {
	m_Name = L"父子关系";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(L"物体");
	DEF_创建物体_Array1D插座_I(L"子物体");
	DEF_创建物体插座_O(L"物体");
}

C_物体父子关系节点::~C_物体父子关系节点() {
}

bool C_物体父子关系节点::f_update() {

	return false;
}

C_节点基类* f_node_加载物体父子关系节点(S_设备环境& ctx, FILE* f) {
	C_物体父子关系节点* node = new C_物体父子关系节点(ctx);
	return node;
}

void f_node_保存物体父子关系节点(C_节点基类* n, FILE* f) {
	C_物体父子关系节点* node = dynamic_cast<C_物体父子关系节点*>(n);
}




C_设置物体数据节点::C_设置物体数据节点(S_设备环境& ctx) : C_节点基类("设置物体数据节点") {
	m_Name = L"设置物体数据";
	m_Ctx = ctx;
	//f_NodeCtx_录物体类节点(this, m_Ob);

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(L"物体");
	DEF_创建引用插座_I(L"数据");

	DEF_创建物体_Array1D插座_O(L"物体");
}

C_设置物体数据节点::~C_设置物体数据节点() {
}

bool C_设置物体数据节点::f_update() {
	auto& inData1 = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto& inData2 = *DEF_引用插座数据(f_get输入插座(2), 0);

	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	objs = inData1;

	uint32 num = inData1.size();
	auto* ob_ptr = inData1.data();
	switch (inData2.m_Type) {
	case E_值类型::e_Type_Mesh: {
		auto mesh = DEF_引用转MESH(inData2);
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set数据(ob_ptr[i], mesh);
			f_ob_set数据(ob_ptr[i], mesh, 1);
			f_ob_set数据(ob_ptr[i], mesh, 2);
			ob_ptr[i]->m_Type = E_物体类型::t_网格;

			f_NodeCtx_录物体类节点(this, ob_ptr[i]);
		}
		break;
	}
	case E_值类型::e_Type_Mesh_1D: {
		auto& mesh = *DEF_引用转MESH_1D(inData2);
		uint32 mesh_num = mesh.size();
		auto* mesh_ptr = mesh.data();
		if (mesh_num >= num) {
			for (uint32 i = 0; i < num; ++i) {
				f_ob_set数据槽数量(ob_ptr[i], 3);
				f_ob_set数据(ob_ptr[i], mesh_ptr[i]);
				f_ob_set数据(ob_ptr[i], f_surface_创建实例(mesh_ptr[i]), 1);
				f_ob_set数据(ob_ptr[i], f_surface_创建实例(mesh_ptr[i]), 2);

				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照面材质(), 1);
				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照线材质(), 2);

				ob_ptr[i]->m_Type = E_物体类型::t_网格;
				f_NodeCtx_录物体类节点(this, ob_ptr[i]);
			}
		}
		else {
			auto mesh_l1 = f_surface_创建实例(mesh_ptr[0]);
			auto mesh_l2 = f_surface_创建实例(mesh_ptr[0]);
			for (uint32 i = 0; i < num; ++i) {
				f_ob_set数据(ob_ptr[i], mesh_ptr[0]);
				f_ob_set数据(ob_ptr[i], mesh_l1, 1);
				f_ob_set数据(ob_ptr[i], mesh_l2, 2);

				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照面材质(), 1);
				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照线材质(), 2);

				ob_ptr[i]->m_Type = E_物体类型::t_网格;
				f_NodeCtx_录物体类节点(this, ob_ptr[i]);
			}
		}
		break;
	}
	case E_值类型::e_Type_Object: {
		auto* mesh = f_ob_fromMesh(DEF_引用转物体(inData2));
		auto* mesh1 = f_ob_fromMesh(DEF_引用转物体(inData2), 1);
		auto* mesh2 = f_ob_fromMesh(DEF_引用转物体(inData2), 2);
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set数据(ob_ptr[i], mesh);
			f_ob_set数据(ob_ptr[i], mesh1, 1);
			f_ob_set数据(ob_ptr[i], mesh2, 2);
			ob_ptr[i]->m_Type = E_物体类型::t_网格;

			f_NodeCtx_录物体类节点(this, ob_ptr[i]);
		}

		break;
	}
	case E_值类型::e_Type_Object_Array1D: {
		auto& 数据物体 = *DEF_引用转物体_1D(inData2);
		uint32 mesh_num = 数据物体.size();
		if (mesh_num >= num) {
			for (uint32 i = 0; i < num; ++i) {

			}
		}
		else {

		}
		break;
	}
	default:
		break;
	}
	
	return false;
}

S_物体* C_设置物体数据节点::f_get虚拟体() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	if(objs.size()) return objs.front();
	return nullptr;
}

void C_设置物体数据节点::f_入回收() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		S_节点数据::m_全局物体set.erase(ob);
	}
}

void C_设置物体数据节点::f_回收() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		S_节点数据::m_全局物体set.insert(ob);
	}
}

C_节点基类* f_node_加载设置物体数据节点(S_设备环境& ctx, FILE* f) {
	C_设置物体数据节点* node = new C_设置物体数据节点(ctx);
	return node;
}
void f_node_保存设置物体数据节点(C_节点基类* n, FILE* f) {
	C_设置物体数据节点* node = dynamic_cast<C_设置物体数据节点*>(n);
}



C_取物体属性节点::C_取物体属性节点(S_设备环境& ctx) : C_节点基类("取物体属性节点", E_节点类型::e_节点Type_物体) {
	m_Name = L"取物体属性";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(L"对象");
	DEF_创建Mat4X4_Array1D插座_O(L"矩阵");
	DEF_创建变换_1D插座_O(L"变换");
}

C_取物体属性节点::~C_取物体属性节点() {
}

bool C_取物体属性节点::f_update() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto& mats = *DEF_Mat44_Array1D插座数据(f_get输出插座(1), 0);
	auto& tranforms = *DEF_变换_1D插座数据(f_get输出插座(2), 0);

	uint32 num = objs.size();
	mats.resize(num);
	tranforms.resize(num);

	auto* ob_ptr = objs.data();
	auto* mat_ptr = mats.data();
	auto* tranform_ptr = tranforms.data();
	for (uint32 i = 0; i < num; ++i) {
		mat_ptr[i] = ob_ptr[i]->f_get矩阵2();
		tranform_ptr[i] = ob_ptr[i]->m_变换;
	}
	return false;
}

C_节点基类* f_node_加载取物体属性节点(S_设备环境& ctx, FILE* f) {
	C_取物体属性节点* node = new C_取物体属性节点(ctx);
	return node;
}

void f_node_保存取物体属性节点(C_节点基类* n, FILE* f) {
	C_取物体属性节点* node = dynamic_cast<C_取物体属性节点*>(n);
}





C_骨头节点::C_骨头节点(S_设备环境& ctx) : C_节点基类("骨头节点", E_节点类型::e_节点Type_骨头) {
	m_Name = L"骨头";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(L"父骨头");
	DEF_创建物体插座_O(L"骨头");

	m_骨头 = f_ob_创建骨骼(nullptr);
	f_NodeCtx_录物体类节点(this);
	f_NodeCtx_录物体类节点(this, m_骨头);


	m_骨头->f_set位置(DEF_骨骼朝向);
}

C_骨头节点::~C_骨头节点() {
}

bool C_骨头节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	//if (socket1->m_有新数据) {
		f_ob_clear子物体(m_骨头);

		if (f_get输入插座(1)->f_isLink()) {
			f_ob_get骨骼数据(m_骨头)->m_长度 = 1.0;

			auto& inData = *DEF_物体插座_1D数据(socket1, 0);
			for (uint32 i=0; i<inData.count; ++i) {
				f_ob_add子物体(m_骨头, inData.ptr_userData[i]);
			}
		}

		f_get输出插座(1)->f_setData(m_骨头);
	//}
	return false;
}

S_物体* C_骨头节点::f_get虚拟体() {
	return m_骨头;
}

void C_骨头节点::f_入回收() {
	f_NodeCtx_get默认场景()->f_remove物体(m_骨头, E_场景物体容器类型::e_集合);
}

void C_骨头节点::f_回收() {
	f_NodeCtx_get默认场景()->f_add物体({ m_骨头 }, E_场景物体容器类型::e_集合);
}

void C_骨头节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_ob_Load物体(m_骨头, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_骨头节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_ob_Save物体(m_骨头, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建骨头节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_骨头节点(ctx);
}

C_节点基类* f_node_加载骨头节点(S_设备环境& ctx, FILE* f) {
	C_骨头节点* node = new C_骨头节点(ctx);
	return node;
}

void f_node_保存骨头节点(C_节点基类* n, FILE* f) {
	C_骨头节点* node = dynamic_cast<C_骨头节点*>(n);
}





C_骨架节点::C_骨架节点(S_设备环境& ctx) : C_节点基类("骨骼节点", E_节点类型::e_节点Type_骨架) {
	m_Name = L"骨架";
	m_Ctx = ctx;

	m_骨架 = f_ob_创建物体(m_Ctx, E_物体类型::t_骨架);

	m_骨骼父物体 = f_ob_创建物体(m_Ctx, E_物体类型::t_包);
	m_虚线 = f_node_创建虚线(m_Ctx);
	{
		m_骨骼物体 = f_ob_创建物体(m_Ctx, E_物体类型::t_网格);
		m_骨节物体 = f_ob_创建物体(m_Ctx, E_物体类型::t_网格);
		
		f_ob_create骨骼虚拟体网格(m_Ctx, m_骨骼物体, m_骨节物体);
		f_node_将现有物体包装成骨骼网格(m_Ctx, m_骨骼物体, m_骨节物体);

		
		//f_ob_add子物体(m_骨骼对象, m_骨架物体);
		//f_ob_add子物体(m_骨骼对象, m_骨节物体);
		
		//m_根骨节 = f_ob_创建物体实例(nullptr, 0);
		//m_根骨节->m_UserData = m_骨架物体;
		//f_ob_add子物体(m_骨节物体, m_根骨节);
		//m_骨架物体->m_UserData = m_根骨节;

		//f_NodeCtx_录物体类节点(this, m_根骨节);
		f_NodeCtx_录物体类节点(this, m_骨骼物体);
		f_NodeCtx_录物体类节点(this, m_骨节物体);
	}
	

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(L"根骨骼");
	DEF_创建引用插座_I(L"约束");
	DEF_创建骨架插座_O(L"骨架");
	f_get输入插座(2)->f_set多输入();
	

	f_node_物体添加到主场景(m_骨架);
	f_NodeCtx_get默认场景()->f_add物体({ m_骨骼物体 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_get默认场景()->f_add物体({ m_骨节物体 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_get默认场景()->f_add物体({ m_虚线 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_录物体类节点(this);


	m_前端显示 = f_alloc_BoolProp(nullptr, L"前端显示");
	m_前端显示.m_私有 = true;


	m_更新方式 = e_节点更新_实时;
}

C_骨架节点::~C_骨架节点() {
	f_node_从主场景移除物体(m_骨架);
	f_NodeCtx_get默认场景()->f_remove物体(m_骨骼物体, E_场景物体容器类型::e_集合);
	f_NodeCtx_get默认场景()->f_remove物体(m_骨节物体, E_场景物体容器类型::e_集合);
	f_NodeCtx_get默认场景()->f_remove物体(m_虚线, E_场景物体容器类型::e_集合);
	//f_ob_销毁物体(m_根骨节);

	f_ob_销毁物体(m_骨骼物体);
	f_ob_销毁物体(m_骨节物体);
	f_ob_销毁物体(m_虚线);

	f_ob_销毁物体(m_骨架);
}

bool C_骨架节点::f_update() {
	S_骨架* 骨架 = f_ob_from骨架(m_骨架);

	auto* socket1 = f_get输入插座(1);
	auto* s = socket1->f_getLinkOutSocket();
	if (s && s->m_有新数据) {
		f_ob_clear子物体(m_骨架);

		auto& inData = *DEF_物体插座_1D数据(f_get输入插座(1), 0);
		if (inData.count == 0) return true;

		uint32 总数量 = 0;
		for (uint32 i = 0; i < inData.count; ++i) {
			f_ob_add子物体(m_骨架, inData.ptr_userData[i]);
		}
		
		f_ob_构建骨骼(m_骨架, m_骨骼物体, m_骨节物体, nullptr);

		//float32* 骨骼长度 = f_buf_F32_ptr(骨架->m_骨骼长度);
		//f_从骨节更新编辑骨骼(m_骨架, m_骨骼物体->m_子物体.data(), m_骨节物体->m_子物体.data(), 0, 骨骼长度, { 0,0,0,1 }, 0);


		//if (f_prop_Bool(S_节点数据状态::g_打开编辑模式)) {
		//	f_NE_骨骼编辑状态颜色设置({ m_骨骼对象 });
		//}
		//else {
		//	f_NE_骨骼物体状态颜色设置({ m_骨骼对象 });
		//}

		f_get输出插座(1)->f_setData(m_骨架);
	}

	


	if (f_prop_Bool(m_前端显示)) {
		auto* m = f_ob_fromMesh(m_骨骼物体);
		m->m_深度控制 = { 0.00001f, 0.01f };
		m = f_ob_fromMesh(m_骨骼物体, 1);
		m->m_深度控制 = { 0.001f, 0.001f };
	
		m = f_ob_fromMesh(m_骨节物体);
		m->m_深度控制 = { 0.001f, 0.001f };
		m = f_ob_fromMesh(m_骨节物体, 1);
		m->m_深度控制 = { 0.001f, 0.001f };
	}
	else {
		auto* m = f_ob_fromMesh(m_骨骼物体);
		m->m_深度控制 = { 1, 0 };
		m = f_ob_fromMesh(m_骨骼物体, 1);
		m->m_深度控制 = { 1, 0 };
	
		m = f_ob_fromMesh(m_骨节物体);
		m->m_深度控制 = { 1, 0 };
		m = f_ob_fromMesh(m_骨节物体, 1);
		m->m_深度控制 = { 1, 0 };
	}


	bool 跳过更新约束 = false;

	if (骨架->m_骨骼长度.m_Mem.m_大小) {
		float32* 骨骼长度 = f_buf_F32_ptr(骨架->m_骨骼长度);
		switch (f_prop_enum(S_节点数据状态::g_骨骼编辑模式)) {
			case E_骨骼编辑模式::e_物体模式: {
				f_NODE_BE_从骨骼更新骨节(m_骨架, m_骨骼物体->m_子物体.data(), m_骨节物体->m_子物体.data());
				m_骨骼物体->m_isUpdate = true;
				m_骨节物体->m_isUpdate = true;
				break;
			}
			case E_骨骼编辑模式::e_姿态模式: {
				//f_NODE_BE_从骨骼更新骨节(m_骨架物体, 骨骼长度, m_骨架物体->f_get矩阵2());
				break;
			}
			case E_骨骼编辑模式::e_骨节编辑模式: {
				骨架->m_IK数量 = 0;
				f_从骨节更新编辑骨骼(m_骨架, m_骨骼物体->m_子物体.data(), m_骨节物体->m_子物体.data(), 0, 骨骼长度, { 0,0,0,1 }, 0);
				跳过更新约束 = true;
				break;
			}
		}
	}
	
	


	m_虚线->m_渲染 = false;
	if (跳过更新约束) return false;


	uint32 num = f_get输入插座(2)->f_getLinkNum();
	if (骨架->m_IK数量 != num) {
		if (骨架->m_IK) {
			free(骨架->m_IK);
		}
		骨架->m_IK = (S_骨骼IK**)calloc(num, sizeof(S_骨骼IK*));
	}
	骨架->m_IK数量 = num;




	//计算IK
	S_Mesh* IK虚线 = f_ob_fromMesh(m_虚线);
	std::vector<vec3> 虚线;
	for (uint32 i = 0; i < num; ++i) {
		auto& rData = *DEF_引用插座数据(f_get输入插座(2), i);

		switch (rData.m_Type)
		{
		case E_值类型::e_Type_IK: {
			S_骨骼IK* IK = DEF_引用转IK(rData);
			骨架->m_IK[i] = IK;

			vec3 vs;
			vec3 ve;
			if (IK->m_始端) vs = f_ob_计算骨骼IK点(IK->m_始端, false);
			else vs = {};
			if (IK->m_末端) ve = f_ob_计算骨骼IK点(IK->m_末端, true);
			else ve = {};

			虚线.push_back(vs);
			虚线.push_back(IK->m_末端坐标);
			break;
		}
		default:
			break;
		}
	}
	f_surface_fill虚线(IK虚线, 虚线);
	m_虚线->m_渲染 = true;
	
	

	if (骨架->m_骨头数量) {
		num = m_骨节物体->m_变换矩阵.m_Mem.m_大小;
		auto* 骨节变换 = f_buf_Mat44_ptr(m_骨节物体->m_变换矩阵);
		auto* 骨骼变换 = f_buf_Mat44_ptr(骨架->m_骨骼变换);
		for (uint32 i = 0; i < num; ++i) {
			//骨节变换[i] = 骨骼变换[i];
		}

	}
	
	return false;
}

void C_骨架节点::f_构建骨骼(S_物体* m_根骨骼)
{
}

S_物体* C_骨架节点::f_get虚拟体() {
	return nullptr;
}

void C_骨架节点::f_入回收() {
	f_NodeCtx_get默认场景()->f_remove物体(m_骨骼物体, E_场景物体容器类型::e_集合);
}

void C_骨架节点::f_回收() {
	f_NodeCtx_get默认场景()->f_add物体({ m_骨节物体 }, E_场景物体容器类型::e_集合);
}

void C_骨架节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_ob_Load物体(m_骨骼父物体, f);
	f_prop_Load(m_前端显示, f);
}

void C_骨架节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_ob_Save物体(m_骨骼父物体, f);
	f_prop_Save(m_前端显示, f);
}

C_节点基类* f_node_创建骨骼节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_骨架节点(ctx);
}

C_节点基类* f_node_加载骨骼节点(S_设备环境& ctx, FILE* f) {
	C_骨架节点* node = new C_骨架节点(ctx);
	return node;
}

void f_node_保存骨骼节点(C_节点基类* n, FILE* f) {
	C_骨架节点* node = dynamic_cast<C_骨架节点*>(n);
}





C_骨骼IK节点::C_骨骼IK节点(S_设备环境& ctx) : C_节点基类("骨骼IK节点", E_节点类型::e_节点Type_约束) {
	m_Name = L"IK";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建骨骼插座_I(L"开始骨骼");
	DEF_创建骨骼插座_I(L"结束骨骼");
	DEF_创建Vec3插座_v1_I(L"控制点");

	DEF_创建IK插座_O(L"IK");


	DEF_Vec3插座数据(f_get输入插座(3)) = {};


	m_虚拟体 = f_node_创建虚拟体(m_Ctx, E_虚拟体类型::E_交叉轴);
	
	f_NodeCtx_get默认场景()->f_add物体({ m_虚拟体 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_录物体类节点(this, m_虚拟体);

	m_Value = f_ob_创建IK();
	f_get输出插座(1)->f_setData(m_Value);

	m_迭代次数 = f_alloc_UI32Prop(nullptr, L"迭代次数");
	m_迭代次数.m_私有 = true;
	f_prop_UI32(m_迭代次数) = 1;

	m_虚拟体类型 = f_alloc_EnumProp(nullptr, { {L"交叉轴",""}, {L"反向轴",""} ,{L"线框球",""} }, L"虚拟体类型");
	m_虚拟体类型.m_私有 = true;

}

C_骨骼IK节点::~C_骨骼IK节点() {
	f_ob_销毁物体(m_虚拟体);
	
	f_ob_销毁IK(m_Value);
	f_prop_Release(m_迭代次数);
}

bool C_骨骼IK节点::f_update() {
	m_Value->m_始端 = DEF_骨骼插座数据(f_get输入插座(1), 0);
	m_Value->m_末端 = DEF_骨骼插座数据(f_get输入插座(2), 0);

	
	m_Value->m_迭代次数 = f_prop_UI32(m_迭代次数);
	if (f_get输入插座(3)->f_isLink()) {
		m_Value->m_末端坐标 = DEF_Vec3插座数据(f_get输入插座(3));
	}
	else {
		m_Value->m_末端坐标 = f_ob_get全局坐标(m_虚拟体, 0);
	}

	switch (f_prop_enum(m_虚拟体类型))
	{
	case E_虚拟体类型::E_交叉轴:
		//f_ob_填充间接绘制(m_虚拟体, { S_虚拟体ID偏移::Indirect_交叉轴 });
		break;
	case E_虚拟体类型::E_方向轴:
		//f_ob_填充间接绘制(m_虚拟体, { S_虚拟体ID偏移::Indirect_方向轴 });
		break;
	case E_虚拟体类型::E_线框球:
		//f_ob_填充间接绘制(m_虚拟体, { S_虚拟体ID偏移::Indirect_线框球 });
		break;
	default:
		break;
	}
	
	return false;
}

S_物体* C_骨骼IK节点::f_get虚拟体() {
	return m_虚拟体;
}

void C_骨骼IK节点::f_入回收() {
	f_NodeCtx_get默认场景()->f_remove物体(m_虚拟体, E_场景物体容器类型::e_集合);
	//f_NodeCtx_get默认场景()->f_remove物体(m_虚线, E_场景物体容器类型::e_集合);
}

void C_骨骼IK节点::f_回收() {
	f_NodeCtx_get默认场景()->f_add物体({ m_虚拟体 }, E_场景物体容器类型::e_集合);
	//f_NodeCtx_get默认场景()->f_add物体(m_虚线, E_场景物体容器类型::e_集合);
}

void C_骨骼IK节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_ob_Load物体(m_虚拟体, f);
}

void C_骨骼IK节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_ob_Save物体(m_虚拟体, f);
}

C_节点基类* f_node_加载骨骼IK节点(S_设备环境& ctx, FILE* f) {
	C_骨骼IK节点* node = new C_骨骼IK节点(ctx);
	return node;
}

void f_node_保存骨骼IK节点(C_节点基类* n, FILE* f) {
	C_骨骼IK节点* node = dynamic_cast<C_骨骼IK节点*>(n);
}



C_物体绑定骨骼节点::C_物体绑定骨骼节点(S_设备环境& ctx) : C_节点基类("物体绑定骨骼节点", E_节点类型::e_节点Type_物体) {
	m_Name = L"骨架";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(L"物体");
	DEF_创建骨架插座_I(L"骨架");
}

C_物体绑定骨骼节点::~C_物体绑定骨骼节点() {
}

bool C_物体绑定骨骼节点::f_update() {
	auto 物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto 骨架 = DEF_骨架插座数据(f_get输入插座(2), 0);

	if (骨架) {
		物体->m_骨架 = 骨架;
	}

	return false;
}

C_节点基类* f_node_加载物体绑定骨骼节点(S_设备环境& ctx, FILE* f) {
	C_物体绑定骨骼节点* node = new C_物体绑定骨骼节点(ctx);
	return node;
}
void f_node_保存物体绑定骨骼节点(C_节点基类* n, FILE* f) {
	C_物体绑定骨骼节点* node = dynamic_cast<C_物体绑定骨骼节点*>(n);
}




C_摄像机节点::C_摄像机节点(S_设备环境& ctx) : C_节点基类(DEF_摄像机节点, E_节点类型::e_节点Type_摄像机) {
	m_Name = L"摄像机";
	m_Ctx = ctx;

	m_Ob = f_node_创建虚拟体网格物体(ctx, E_物体类型::t_虚拟体);
	m_Ob->m_Name = L"摄像机虚拟体";
	f_NodeCtx_录物体类节点(this, m_Ob);
	m_摄像机 = (S_摄像机*)f_ob_创建物体(m_Ctx, E_物体类型::t_摄像机);
	m_摄像机->m_Name = L"摄像机";
	f_ob_add子物体(m_Ob, m_摄像机);

	f_node_物体加入全局容器中(m_摄像机);
	f_node_物体加入全局容器中(m_Ob);


	m_动画曲线列表 = f_an_创建曲线层();

	C_插座基类* socket;
	DEF_创建iVec2插座_Ip(L"分辨率", &m_摄像机->m_分辨率);
	DEF_创建F32插座_I(L"视野角度", &m_摄像机->m_视角);

	DEF_创建物体插座_O(L"摄像机");

}

C_摄像机节点::~C_摄像机节点() {
	f_node_物体从全局容器移除(m_摄像机);
	f_ob_销毁摄像机(m_摄像机);
	f_ob_销毁物体(m_Ob);
}

bool C_摄像机节点::f_update() {
	float32 视野角度 = DEF_F32插座数据(f_get输入插座(2));
	vec2 比例 = { float32(m_摄像机->m_分辨率.x), float32(m_摄像机->m_分辨率.y) };
	m_摄像机->f_set宽高比(比例);
	m_摄像机->f_set视角(视野角度);
	

	f_node_设置摄像机虚拟网格(m_Ob, m_摄像机);
	auto mesh = f_ob_fromMesh(m_Ob, 0);
	m_Ob->m_Bound = f_surface_计算包围盒(mesh, nullptr);

	f_get输出插座(1)->f_setData(m_Ob);
	return false;
}

std::string C_摄像机节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	std::string name = f_getName();


	if (m_区域父节点) {
		m_区域父节点->m_Code;
		//m_区域父节点->m_ReleaseCode += f_代码构建_销毁_Array(name);
		return "";
	}
	return m_Code;
}

S_动画曲线组* C_摄像机节点::f_getAN曲线() {
	f_an_清除曲线通道(m_动画曲线列表);

	if (m_Ob->m_位置) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
	}
	if (m_Ob->m_旋转) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
	}
	if (m_Ob->m_缩放) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
	}
	return m_动画曲线列表;
}

S_物体* C_摄像机节点::f_get虚拟体() {
	return m_Ob;
}

void C_摄像机节点::f_入回收() {
	m_Ob->m_渲染 = false;
	f_node_移除虚拟体(m_Ob);

}

void C_摄像机节点::f_回收() {
	m_Ob->m_渲染 = true;
	//f_node_创建摄像机虚拟体(m_Ob);
}

void C_摄像机节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_ob_Load物体(m_Ob, f);
}

void C_摄像机节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_ob_Save物体(m_Ob, f);
}
C_节点基类* f_node_创建摄像机节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_摄像机节点(ctx);
}

C_节点基类* f_node_加载摄像机节点(S_设备环境& ctx, FILE* f) {
	C_摄像机节点* node = new C_摄像机节点(ctx);
	return node;
}

void f_node_保存摄像机节点(C_节点基类* n, FILE* f) {
	C_摄像机节点* node = dynamic_cast<C_摄像机节点*>(n);
}





C_物体拷贝节点::C_物体拷贝节点(S_设备环境& ctx) : C_节点基类("物体拷贝节点", E_节点类型::e_节点Type_物体) {
	m_GPU环境 = ctx;
	m_Ctx = ctx;

	m_Name = L"物体拷贝节点";

	m_当前拷贝物体根物体 = f_ob_创建物体(m_GPU环境, E_物体类型::t_包);
	f_NodeCtx_get默认场景()->f_add物体({ m_当前拷贝物体根物体 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_录物体类节点(this);

	
	f_node_物体添加到主场景(m_当前拷贝物体根物体);



	C_插座基类* socket;

	DEF_创建物体_1D插座_I(L"物体");
	DEF_创建UI32插座_I(L"数量");

	DEF_创建物体_1D插座_O(L"新物体");

	m_是否实例 = f_alloc_BoolProp(nullptr, L"是否实例");
	m_是否实例.m_私有 = true;
	f_prop_Bool(m_是否实例) = true;

	DEF_UI32插座数据(f_get输入插座(2), 0) = 1;
}

C_物体拷贝节点::~C_物体拷贝节点() {
	f_prop_Release(m_是否实例);

	f_node_从主场景移除物体(m_当前拷贝物体根物体);
	f_ob_销毁物体(m_当前拷贝物体根物体);
}

bool C_物体拷贝节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	if (socket1->m_有新数据 || socket2->m_有新数据 || 1) {
		auto* 输入物体组 = DEF_物体插座_1D数据(socket1, 0);
		uint32	数量 = DEF_UI32插座数据(socket2, 0);
		if(数量 >= -1) 数量 = 0;
		数量 = DEF_Max(数量, 1);


		auto* newObs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
		f_node_删除物体(newObs);
		

		auto* scene = f_NodeCtx_get默认场景();
		//新物体数量改变 线移除可能多出的物体
		//uint32 输入组数量 = 输入物体组.size();
		//uint32 实例总数 = 输入组数量 * 数量;
		f_ob_清除子物体(m_当前拷贝物体根物体);
		

		f_NE_拷贝物体(输入物体组, 数量, m_当前拷贝物体根物体, newObs, f_prop_Bool(m_是否实例), m_Ctx);
		//f_node_网格绘制属性设置(m_当前拷贝物体根物体);
		f_scene_更新物体渲染(f_NodeCtx_get默认场景(), m_当前拷贝物体根物体);
	}
	
	return false;
}

S_物体* C_物体拷贝节点::f_get虚拟体() {
	return m_当前拷贝物体根物体;
}

void C_物体拷贝节点::f_入回收() {
	f_NodeCtx_get默认场景()->f_remove物体(m_当前拷贝物体根物体, E_场景物体容器类型::e_集合);
	//f_NodeCtx_get默认场景()->f_remove物体(m_虚线, E_场景物体容器类型::e_集合);
}

void C_物体拷贝节点::f_回收() {
	f_NodeCtx_get默认场景()->f_add物体({ m_当前拷贝物体根物体 }, E_场景物体容器类型::e_集合);
	//f_NodeCtx_get默认场景()->f_add物体(m_虚线, E_场景物体容器类型::e_集合);
}

void C_物体拷贝节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_是否实例, f);
}

void C_物体拷贝节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_是否实例, f);
}

C_节点基类* f_node_创建物体拷贝节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体拷贝节点(ctx);
}

C_节点基类* f_node_加载物体拷贝节点(S_设备环境& ctx, FILE* f) {
	C_物体拷贝节点* node = new C_物体拷贝节点(ctx);
	return node;
}

void f_node_保存物体拷贝节点(C_节点基类* n, FILE* f) {
	C_物体拷贝节点* node = dynamic_cast<C_物体拷贝节点*>(n);
}














C_设置物体矩阵节点::C_设置物体矩阵节点(S_设备环境& ctx) : C_节点基类("设置物体矩阵节点") {
	m_Name = L"设置物体矩阵节点";
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(L"物体");
	DEF_创建Mat4X4_1D插座_I(L"矩阵");

	DEF_创建物体_1D插座_O(L"物体");
}

C_设置物体矩阵节点::~C_设置物体矩阵节点() {

}

bool C_设置物体矩阵节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	if(socket1->f_isLink() == false) return false; 

	auto* objs = DEF_物体插座_1D数据(f_get输入插座(1), 0);
	auto* mats = DEF_Mat44插座_1D数据(f_get输入插座(2), 0);

	f_get输出插座(1)->f_setData(objs);
	uint32 num = objs->count;
	
	if (mats->count >= num) {
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set矩阵(objs->ptr_userData[i], mats->ptr_userData[i], objs->ptr_userData[i]->m_实例ID);
		}
	}
	else {
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set矩阵(objs->ptr_userData[i], mats->ptr_userData[0], objs->ptr_userData[i]->m_实例ID);
		}
	}
	return false;
}

void C_设置物体矩阵节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_设置物体矩阵节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);

	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建设置物体矩阵节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体矩阵节点(ctx);
}

C_节点基类* f_node_加载设置物体矩阵节点(S_设备环境& ctx, FILE* f) {
	C_设置物体矩阵节点* node = new C_设置物体矩阵节点(ctx);
	return node;
}

void f_node_保存设置物体矩阵节点(C_节点基类* n, FILE* f) {
	C_设置物体矩阵节点* node = dynamic_cast<C_设置物体矩阵节点*>(n);
}



C_取物体矩阵节点::C_取物体矩阵节点(S_设备环境 & ctx) : C_节点基类(DEF_取物体矩阵节点) {
	m_Name = L"取矩阵";
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(L"物体");
	DEF_创建Mat4X4_1D插座_O(L"矩阵");
}
C_取物体矩阵节点::~C_取物体矩阵节点() {

}
bool C_取物体矩阵节点::f_update() {
	auto* socket1 = f_get输入插座(1);

	auto* 矩阵 = DEF_Mat44插座_1D数据(f_get输出插座(1), 0);
	if (socket1->f_isLink()) {
		auto* 物体 = DEF_物体插座_1D数据(f_get输入插座(1), 0);
		
		f_core_array_resize((S_Array*)矩阵, 物体->count);
		for (uint32 i = 0; i < 物体->count; ++i) {
			矩阵->ptr_userData[i] = f_ob_get变换矩阵(物体->ptr_userData[i]);
		}
	}
	else {
		f_core_array_resize((S_Array*)矩阵, 0);
	}
	
	return false;
}

void C_取物体矩阵节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_取物体矩阵节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);
	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建取物体矩阵节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体矩阵节点(ctx);
}
C_节点基类* f_node_加载取物体矩阵节点(S_设备环境& ctx, FILE* f) {
	C_取物体矩阵节点* node = new C_取物体矩阵节点(ctx);
	return node;
}
void f_node_保存取物体矩阵节点(C_节点基类* n, FILE* f) {
	C_取物体矩阵节点* node = dynamic_cast<C_取物体矩阵节点*>(n);
}




C_设置物体变换节点::C_设置物体变换节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体变换节点) {
	m_Name = L"设置物体变换节点";
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(L"物体");
	//DEF_创建引用插座_I(L"网格物体");

	DEF_创建Vec3_1D插座_I(L"移动");
	DEF_创建Vec3_1D插座_I(L"旋转");
	DEF_创建Vec3_1D插座_I(L"缩放");

	DEF_创建物体_1D插座_O(L"引用物体");


	auto& l = *DEF_Vec3插座_1D数据(f_get输入插座(2));
	auto& r = *DEF_Vec3插座_1D数据(f_get输入插座(3));
	auto& s = *DEF_Vec3插座_1D数据(f_get输入插座(4));
	l.ptr_userData[0] = {0,0,0};
	r.ptr_userData[0] = {0,0,0};
	s.ptr_userData[0] = {1,1,1};

	m_X暂存 = f_vec3_array_alloc(1);
	m_Y暂存 = f_vec3_array_alloc(1);
	m_Z暂存 = f_vec3_array_alloc(1);


	m_缓存物体组 = nullptr;
}

C_设置物体变换节点::~C_设置物体变换节点() {
	f_core_array_free((S_Array*)m_X暂存);
	f_core_array_free((S_Array*)m_Y暂存);
	f_core_array_free((S_Array*)m_Z暂存);
}

bool C_设置物体变换节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	S_OBArray* in物体数据1 = DEF_物体插座_1D数据(f_get输入插座(1), 0);
	
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* socket4 = f_get输入插座(4);
	auto& 移动 = *DEF_Vec3插座_1D数据(socket2);
	auto& 旋转 = *DEF_Vec3插座_1D数据(socket3);
	auto& 缩放 = *DEF_Vec3插座_1D数据(socket4);

	//if (socket2->f_isLink() == false) {
	//	f_core_array_resize((S_Array*)&移动, 1);
	//	移动.ptr_userData[0] = {0,0,0};
	//}
	//if (socket3->f_isLink() == false) {
	//	f_core_array_resize((S_Array*)&旋转, 1);
	//	旋转.ptr_userData[0] = {0,0,0};
	//}
	//if (socket4->f_isLink() == false) {
	//	f_core_array_resize((S_Array*)&缩放, 1);
	//	缩放.ptr_userData[0] = {1,1,1};
	//}


	if (socket1->f_isLink()) {
		uint32 num = in物体数据1->count;
		if (num) {
			auto* ob = in物体数据1->ptr_userData;

			bool 移动单例 = 移动.count < num;
			bool 旋转单例 = 旋转.count < num;
			bool 缩放单例 = 缩放.count < num;

			for (uint32 i = 0; i < num; ++i) {
				f_物体变换(ob[i], 移动.ptr_userData[移动单例 ? 0 : i], 旋转.ptr_userData[旋转单例 ? 0 : i], 缩放.ptr_userData[缩放单例 ? 0 : i], 0);
			}
		}

		f_get输出插座(1)->f_setData(in物体数据1);
	}
	else {
		if (m_缓存物体组) {
			uint32 num = m_缓存物体组->count;

			auto* ob = m_缓存物体组->ptr_userData;

			bool 移动单例 = 移动.count < num;
			bool 旋转单例 = 旋转.count < num;
			bool 缩放单例 = 缩放.count < num;

			for (uint32 i = 0; i < num; ++i) {
				//f_物体变换(ob[i], 移动.ptr_userData[移动单例 ? 0 : i], 旋转.ptr_userData[旋转单例 ? 0 : i], 缩放.ptr_userData[缩放单例 ? 0 : i], 0);
			}

			m_缓存物体组 = nullptr;
		}
		f_get输出插座(1)->f_setData(m_缓存物体组);
	}
	
	
	return false;
}

void C_设置物体变换节点::f_物体变换(S_物体* ob, const vec3& loc, const vec3& rot, const vec3& scal, uint32 offset) {
	ob->f_set位置(loc, offset);
	ob->f_set旋转(rot, offset);
	ob->f_set缩放(scal, offset);
}

void C_设置物体变换节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			//下一次读取数据指针 = f_prop_Load(m_外部加载, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
	//f_core_array_load((S_Array*)m_X暂存, f);
	//f_core_array_load((S_Array*)m_Y暂存, f);
	//f_core_array_load((S_Array*)m_Z暂存, f);
}

void C_设置物体变换节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_外部加载, 块);

	f_file_保存文件块(f, 文件块, 块);
	//f_core_array_save((S_Array*)m_X暂存, f);
	//f_core_array_save((S_Array*)m_Y暂存, f);
	//f_core_array_save((S_Array*)m_Z暂存, f);
}

C_节点基类* f_node_创建设置物体变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体变换节点(ctx);
}

C_节点基类* f_node_加载设置物体变换节点(S_设备环境& ctx, FILE* f) {
	C_设置物体变换节点* node = new C_设置物体变换节点(ctx);
	return node;
}

void f_node_保存设置物体变换节点(C_节点基类* n, FILE* f) {
	C_物体拷贝节点* node = dynamic_cast<C_物体拷贝节点*>(n);
}






C_取物体变换节点::C_取物体变换节点(S_设备环境& ctx) : C_节点基类(DEF_取物体变换节点, E_节点类型::e_节点Type_计算) {
	m_Name = L"物体变换";
	m_Ctx = ctx;


	C_插座基类* socket;
	DEF_创建物体_1D插座_I(L"物体");
	DEF_创建Vec3_1D插座_O(L"移动", nullptr);
	DEF_创建Vec3_1D插座_O(L"旋转", nullptr);
	DEF_创建Vec3_1D插座_O(L"缩放", nullptr);


}

C_取物体变换节点::~C_取物体变换节点() {
}

bool C_取物体变换节点::f_update() {
	auto* socket = f_get输入插座(1);

	auto* x = DEF_Vec3插座_1D数据(f_get输出插座(1), 0);
	auto* y = DEF_Vec3插座_1D数据(f_get输出插座(2), 0);
	auto* z = DEF_Vec3插座_1D数据(f_get输出插座(3), 0);

	auto* 物体 = DEF_物体插座_1D数据(f_get输入插座(1), 0);

	if (socket->f_isLink()) {
		f_core_array_resize((S_Array*)x, 物体->count);
		f_core_array_resize((S_Array*)y, 物体->count);
		f_core_array_resize((S_Array*)z, 物体->count);

		for (uint32 i = 0; i < 物体->count; ++i) {
			x->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.location;
			y->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.rotation;
			z->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.scale;
		}

		m_缓存物体组 = 物体;
	}
	else {
		f_core_array_resize((S_Array*)x, 1);
		f_core_array_resize((S_Array*)y, 1);
		f_core_array_resize((S_Array*)z, 1);

		x->ptr_userData[0] = {};
		y->ptr_userData[0] = {};
		z->ptr_userData[0] = { 1,1,1 };

		m_缓存物体组 = nullptr;
	}

	return false;
}

void C_取物体变换节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_4, S_节点数据::g_文件版本号)) {
			//下一次读取数据指针 = f_prop_Load(m_外部加载, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_取物体变换节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_外部加载, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建取物体变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体变换节点(ctx);
}

C_节点基类* f_node_加载取物体变换节点(S_设备环境& ctx, FILE* f) {
	C_取物体变换节点* node = new C_取物体变换节点(ctx);
	return node;
}

void f_node_保存取物体变换节点(C_节点基类* n, FILE* f) {
	C_取物体变换节点* node = dynamic_cast<C_取物体变换节点*>(n);
}




C_设置摄像机属性节点::C_设置摄像机属性节点(S_设备环境 & ctx) : C_节点基类(DEF_设置摄像机属性节点) {
	m_Name = L"设置摄像机";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(L"摄像机");
	DEF_创建Vec3插座_I(L"视点", nullptr);
	DEF_创建Vec3插座_I(L"旋转", nullptr);
	DEF_创建F32插座_I(L"视点距离", nullptr);
	DEF_创建F32插座_I(L"视野", nullptr);

	DEF_创建物体插座_O(L"摄像机");

	//m_视点距离 = f_alloc_F32Prop(nullptr, L"视点距离");
	//m_视点距离.m_私有 = true;
	DEF_F32插座数据(f_get输入插座(4)) = -5;
	DEF_F32插座数据(f_get输入插座(5)) = 45;
}

C_设置摄像机属性节点::~C_设置摄像机属性节点() {
	//f_prop_Release(m_视点距离);
}

bool C_设置摄像机属性节点::f_update() {
	auto* 摄像机 = DEF_物体插座数据(f_get输入插座(1), 0);

	if (摄像机 && 摄像机->m_Type == E_物体类型::t_摄像机) {
		S_摄像机* camera = (S_摄像机*)摄像机;

		auto* socket2 = f_get输入插座(2);
		auto* socket3 = f_get输入插座(3);
		//auto* socket4 = f_get输入插座(4);

		camera->m_视点 = DEF_Vec3插座数据(socket2);
		camera->m_变换.rotation = DEF_Vec3插座数据(socket3);
		camera->m_眼睛偏移 = {};
		
		//if (socket3->f_isLink()) {
		camera->m_视点距离 = DEF_F32插座数据(f_get输入插座(4));
		camera->m_视角 = DEF_F32插座数据(f_get输入插座(5));
		//camera->m_视点距离 = f_prop_F32(m_视点距离);
		camera->m_isUpdate = true;
		//}
	}
	else {
		摄像机 = nullptr;
		
	}
	f_get输出插座(1)->f_setData(摄像机);
	return false;
}

void C_设置摄像机属性节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);
	//f_prop_Load(m_视点距离, f);
}

void C_设置摄像机属性节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	//f_prop_Save(m_视点距离, f);
}

C_节点基类* f_node_创建设置摄像机属性节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置摄像机属性节点(ctx);
}

C_节点基类* f_node_加载设置摄像机属性节点(S_设备环境& ctx, FILE* f) {
	C_设置摄像机属性节点* node = new C_设置摄像机属性节点(ctx);
	return node;
}

void f_node_保存设置摄像机属性节点(C_节点基类* n, FILE* f) {
	C_设置摄像机属性节点* node = dynamic_cast<C_设置摄像机属性节点*>(n);
}





static void f_转换blender的动画移动轴向(S_动画曲线组* 通道) {
	
	uint32 t = 0;
	//for (auto c = 通道->曲线通道; c; c = c->ptr_尾, ++t) {
		//S_曲线通道* cuvre = (S_曲线通道*)(c->ptr_userData);
		//if (cuvre->count) {
			/*for (auto p = cuvre->point; p; p = p->ptr_尾) {
				S_CurvePoint* cp = (S_CurvePoint*)p->ptr_userData;

				switch (t) {
				case 2:
					//cp->value *= -1;
					break;

				}
			}*/
		//}
	//}
}

static void f_转换blender的动画旋转轴向(S_动画曲线组* 通道) {
	uint32 t = 0;
	//for (auto c = 通道->曲线通道; c; c = c->ptr_尾, ++t) {
	//	S_曲线通道* cuvre = (S_曲线通道*)(c->ptr_userData);
		//if (cuvre->count) {
			/*for (auto p = cuvre->point; p; p = p->ptr_尾) {
				S_CurvePoint* cp = (S_CurvePoint*)p->ptr_userData;

				switch (t) {
				//case 0:
				case 2:
					//cp->value = -cp->value;
					break;
				}
			}*/
		//}
	//}
}

static void f_转换blender的动画交换轴向(S_动画曲线组* 通道) {
	f_core_list_moveItem(通道->曲线通道, 1, 2);
}

static void f_转换blender的动画轴向缩放(S_动画曲线组* 通道) {
	//f_core_moveItem(通道->曲线通道, 1, 2);
	uint32 t = 0;
	//for (auto c = 通道->曲线通道; c; c = c->ptr_尾, ++t) {
	//	S_曲线通道* cuvre = (S_曲线通道*)(c->ptr_userData);
	//	if (cuvre->count) {
			/*for (auto p = cuvre->point; p; p = p->ptr_尾) {
				S_CurvePoint* cp = (S_CurvePoint*)p->ptr_userData;

				switch (t) {
				case 2:
					//cp->value = -cp->value;
					break;
				}
			}*/
	//	}
	//}
}

static void f_转换blender关键帧(S_动画曲线组* 通道) {
	//f_core_moveItem(通道->曲线通道, 1, 2);
	uint32 t = 0;
	//for (auto c = 通道->曲线通道; c; c = c->ptr_尾, ++t) {
	//	S_曲线通道* cuvre = (S_曲线通道*)(c->ptr_userData);
	//	if (cuvre->count) {
			/*for (auto p = cuvre->point; p; p = p->ptr_尾) {
				S_CurvePoint* cp = (S_CurvePoint*)p->ptr_userData;

				switch (t) {
				case 2:
					//cp->value = -cp->value;
					break;
				}
			}*/
	//	}
	//}
}

static void f_递归所有物体(S_物体* ob) {
	if (ob->m_Type == E_物体类型::t_骨骼) {
		vec3 loc = {};
		if (ob->m_位置) {
			//ob->m_变换.location = f_an_曲线值(ob->m_位置, 0);
		}
		vec3 rot = {};
		if (ob->m_旋转) {
			//ob->m_变换.rotation = f_an_曲线值(ob->m_旋转, 0);
		}
		vec3 scale = { 1,1,1 };
		if (ob->m_缩放) {
			//ob->m_变换.scale = f_an_曲线值(ob->m_缩放, 0);
		}
	}
	//if (物体->m_缩放) f_转换blender的动画轴向(物体->m_缩放);
	for (auto& e : ob->m_子物体) {
		f_递归所有物体(e);
	}
}




C_外部加载物体节点::C_外部加载物体节点(S_设备环境& ctx) : C_节点基类(DEF_外部加载物体节点, E_节点类型::e_节点Type_物体) {
	m_Name = L"外部物体";
	m_Ctx = ctx;
	m_ObPtr = nullptr;


	C_插座基类* socket;
	DEF_创建物体_Array1D插座_O(L"物体");

	m_是否递归目录 = f_alloc_BoolProp(nullptr, L"递归目录");
	m_是否递归目录.m_私有 = true;
	f_prop_Bool(m_是否递归目录) = false;

	m_是否序列 = f_alloc_BoolProp(nullptr, L"序列");
	m_是否序列.m_私有 = true;
	f_prop_Bool(m_是否序列) = false;

	m_Path = f_alloc_PathProp(nullptr, L"文件路径");
	m_Path.m_私有 = true;

	m_文件类型 = f_alloc_EnumProp(nullptr, { {L"FBX", ""}, {L"OBJ", ""} }, L"文件类型", 0);
	m_文件类型.m_私有 = true;

	m_瓦片 = f_alloc_EnumProp(nullptr, { {L"XY", ""}, {L"XZ", ""} }, L"瓦片", 1);
	m_瓦片.m_私有 = true;

	m_网格类型 = f_alloc_EnumProp(nullptr, { {L"多边形", ""}, {L"网格", ""} }, L"面类型", 1);
	m_网格类型.m_私有 = true;
	
}

C_外部加载物体节点::~C_外部加载物体节点() {
	f_prop_Release(m_是否递归目录);
	f_prop_Release(m_是否序列);
	f_prop_Release(m_Path);
	f_prop_Release(m_文件类型);
	f_prop_Release(m_瓦片);
}

bool C_外部加载物体节点::f_update() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	m_ObPtr = &objs;

	if (f_prop_Path(m_Path).string() != m_上一次加载路径) {
		f_node_从主场景移除物体(objs);
		objs.clear();

		m_上一次加载路径 = f_prop_Path(m_Path).string();


		auto 扩展名 = f_prop_Path(m_Path).extension();
		if (f_prop_Bool(m_是否递归目录)) {
			f_递归加载物体(m_上一次加载路径);
		}
		else {
			f_加载物体(m_上一次加载路径);
		}


		uint32 num = objs.size();
		for (uint32 i = 0; i < num; ++i) {
			//f_node_物体节点创建物体数据(objs[i]);
			f_ob_set材质(objs[i], f_NodeCtx_get基本光照描边材质(), 0);
			f_ob_set材质(objs[i], f_NodeCtx_get基本光照面材质(), 1);
			f_ob_set材质(objs[i], f_NodeCtx_get逐顶点点材质(), 2);
			f_ob_set材质(objs[i], f_NodeCtx_get逐顶点线段材质(), 3);

			f_node_网格绘制属性设置(objs[i]);
			f_NodeCtx_录物体类节点(this, objs[i]);

			f_node_物体加入全局容器中(objs[i]);
		}


		num = DEF_Min(m_变换组.size(), num);
		f_get输出插座(1)->m_有新数据 = true;
		for (uint32 i = 0; i < num; ++i) {
			objs[i]->m_变换 = m_变换组[i];
		}
		m_变换组.clear();


		if (m_显示数据) {
			f_node_物体添加到主场景(objs);
		}
	}

	if (!m_显示数据) {
		f_node_从主场景移除物体(objs);
	}
	return false;
}

static std::mutex g_物体添加锁;
void C_外部加载物体节点::f_递归加载物体(std::string path) {
	S_目录文件包 dir;
	f_file_get目录下所有文件名(path, dir, ".obj");
	
	uint32 num = dir.目录.size();
#pragma omp parallel for
	for(int32 i=0; i<num; ++i){
	//for (auto& name : dir.目录) {
		f_递归加载物体(path + "/" + f_WStringToString(dir.目录[i]));
	}
	//f_file_get目录下所有目录名(m_上一次加载路径, dir);

	num = dir.文件.size();
#pragma omp parallel for
	for (int32 i = 0; i < num; ++i) {
	//for (auto& name : dir.文件) {
		S_物体* ob = f_ob_loadOBJ(path + "/" + f_WStringToString(dir.文件[i]), m_Ctx);
		
		g_物体添加锁.lock();
		(*m_ObPtr).emplace_back(ob);
		std::cout << "path +   " << path + "/" + f_WStringToString(dir.文件[i]) << std::endl;
		g_物体添加锁.unlock();
	}

}

void C_外部加载物体节点::f_加载物体(std::string path) {
	auto 扩展名 = f_file_文件扩展名(path);

	if (扩展名 == ".ms") {
		//f_ob_loadFBX(objs, m_Path, m_Ctx);
	}
	else if (扩展名 == ".fbx" || 扩展名 == ".FBX") {
		f_ob_loadFBX((*m_ObPtr), m_上一次加载路径, m_Ctx);

		uint32 num = (*m_ObPtr).size();
		for (uint32 i = 0; i < num; ++i) {
			S_物体* 骨头物体 = f_递归构建骨骼网格体((*m_ObPtr)[i], m_Ctx);
			//f_递归所有物体(objs[i]);
			/*for (auto& e : objs[i]->m_子物体) {
				if (e->m_Type == E_物体类型::t_骨骼) {
					uint32 开始ID = 0;
					f_ob_构建骨骼虚拟体实例ID(e, 开始ID);
					f_ob_create骨骼虚拟体网格(m_Ctx, e);
					f_node_物体节点创建物体数据(e);
				}
			}*/
			//f_ob_绑定网格骨骼(objs[i], 骨头物体, 0);
			((*m_ObPtr)[i])->m_Bound = f_surface_计算包围盒(f_ob_fromMesh((*m_ObPtr)[i]));

			f_node_物体加入全局容器中((*m_ObPtr)[i]);
		}
	}
	else if (扩展名 == ".obj") {

	}
}

void C_外部加载物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		
		if (f_file_版本对比(文件块, S_节点数据::g_低版本号_1, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_是否递归目录, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_是否序列, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件类型, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_瓦片, 下一次读取数据指针);

			//auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
			
			m_变换组.clear();
			下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, m_变换组, false);

		}
		else if (f_file_版本对比(文件块, S_节点数据::g_低版本号_0, S_节点数据::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_是否递归目录, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_是否序列, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_文件类型, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_瓦片, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_外部加载物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_是否递归目录, 块);
	f_prop_Save(m_是否序列, 块);
	f_prop_Save(m_文件类型, 块);
	f_prop_Save(m_Path, 块);
	f_prop_Save(m_瓦片, 块);


	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	m_变换组.clear();
	for(auto& ob : objs) m_变换组.push_back(ob->m_变换);
	f_文件块_写序列数据块(块, m_变换组, false);

	f_file_保存文件块(f, 文件块, 块);
}

S_物体* C_外部加载物体节点::f_get虚拟体() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	if (objs.size()) {
		return objs[0];
	}
	return nullptr;
}

void C_外部加载物体节点::f_入回收() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		f_NodeCtx_清除物体类节点(ob);
		f_NodeCtx_get默认场景()->f_remove物体(ob, E_场景物体容器类型::e_集合);
		f_node_物体从全局容器移除(ob);
	}
}

void C_外部加载物体节点::f_回收() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		f_NodeCtx_录物体类节点(this, ob);
		f_NodeCtx_get默认场景()->f_add物体({ ob }, E_场景物体容器类型::e_集合);
		f_node_物体加入全局容器中(ob);
	}
}

void C_外部加载物体节点::f_Show(bool open) {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		ob->m_渲染 = open;
	}
}

C_节点基类 * f_node_创建外部加载物体节点(S_设备环境 & ctx, C_节点树 * 子节点树) {
	return new C_外部加载物体节点(ctx);
}

C_节点基类* f_node_加载外部加载物体节点(S_设备环境& ctx, FILE* f) {
	C_外部加载物体节点* node = new C_外部加载物体节点(ctx);
	
	f_prop_Load(node->m_Path, f);




	return node;
}

void f_node_保存外部加载物体节点(C_节点基类* n, FILE* f) {
	C_外部加载物体节点* node = dynamic_cast<C_外部加载物体节点*>(n);

	f_prop_Save(node->m_Path, f);
	//f_保存字符串(f, node->m_Path);
}





C_物体对称节点::C_物体对称节点(S_设备环境& ctx) : C_节点基类("物体对称节点") {
	m_Name = L"物体对称";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建引用插座_I(L"物体");
	DEF_创建Vec3插座_v1_I(L"坐标");

	DEF_创建物体_Array1D插座_O(L"新物体");
}

C_物体对称节点::~C_物体对称节点() {
}

bool C_物体对称节点::f_update() {
	auto& 引用插座数据 = *DEF_引用插座数据(f_get输入插座(1), 0);
	auto& coord = DEF_Vec3插座数据(f_get输入插座(2));

	std::vector<S_物体*> 新物体;
	switch (f_get输出插座(1)->m_Type)
	{
	case E_值类型::e_Type_Object_Array1D: {
		新物体 = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
		break;
	}
	case E_值类型::e_Type_骨骼: {
		S_物体* b = DEF_骨骼插座数据(f_get输出插座(1), 0);
		if(b) 新物体.push_back(b);
	}
	default:
		break;
	}
	f_NodeCtx_get默认场景()->f_remove物体(新物体, E_场景物体容器类型::e_集合);
	

	for (auto& e : 新物体) f_NodeCtx_删除物体到回收站(e);
	新物体.clear();

	std::vector<S_物体*> obs;
	
	switch (引用插座数据.m_Type)
	{
	case E_值类型::e_Type_骨架: {
		obs.push_back(f_node_创建骨架物体(m_Ctx));
		auto 骨架 = DEF_引用转骨架(引用插座数据);
		break;
	}
	case E_值类型::e_Type_骨骼: {
		obs.push_back(DEF_引用转骨骼(引用插座数据));
		//f_NE_拷贝物体(obs, 1, 新物体, false, m_Ctx);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_骨骼);

		bool 对称轴[3] = { true, false, false };
		f_NE_对称物体(obs, 新物体, 对称轴, { 0,0,0 });

		f_get输出插座(1)->f_setData(新物体[0]);
		break;
	}
	case E_值类型::e_Type_Object_Array1D: {
		//f_NE_拷贝物体(obs, 1, 新物体, false, m_Ctx);
		
		break;
	}
	default:
		break;
	}

	
	
	for (auto& e : 新物体) f_NodeCtx_录物体类节点(this, e);
	//f_NodeCtx_get默认场景()->f_add物体(新物体, E_场景物体容器类型::e_集合);
	
	return false;
}


C_节点基类* f_node_加载物体对称节点(S_设备环境& ctx, FILE* f) {
	C_物体对称节点* node = new C_物体对称节点(ctx);
	return node;
}

void f_node_保存物体对称节点(C_节点基类* n, FILE* f) {
	C_物体对称节点* node = dynamic_cast<C_物体对称节点*>(n);
}




C_取物体材质节点::C_取物体材质节点(S_设备环境& ctx) : C_节点基类(DEF_取物体材质节点) {
	m_Name = L"取物体材质";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(L"物体");
	DEF_创建I8_1D插座_I(L"槽");

	DEF_创建材质_1D插座_O(L"材质");
}

C_取物体材质节点::~C_取物体材质节点() {
}

bool C_取物体材质节点::f_update() {
	auto& obs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto* ms = DEF_材质插座_1D数据(f_get输出插座(1), 0);

	uint32 num = obs.size();
	if (!num) {
		f_core_array_clear((S_Array*)ms);
		return false;
	}

	if (num > 1) {
		f_core_array_resize((S_Array*)ms, num);
		auto obPtr = obs.data();
		auto mPtr = ms->ptr_userData;
		for (uint32 i = 0; i < num; ++i) {
			mPtr[i] = f_ob_fromMesh(obPtr[i])->m_Material;
		}
	}
	else {
		f_core_array_resize((S_Array*)ms, 1);
		ms->ptr_userData[0] = f_ob_fromMesh(obs[0])->m_Material;
	}
	
	return false;
}

C_节点基类* f_node_创建取物体材质节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体对称节点(ctx);
}

C_节点基类* f_node_加载取物体材质节点(S_设备环境& ctx, FILE* f) {
	C_取物体材质节点* node = new C_取物体材质节点(ctx);
	return node;
}

void f_node_保存取物体材质节点(C_节点基类* n, FILE* f) {
	C_取物体材质节点* node = dynamic_cast<C_取物体材质节点*>(n);
}




C_取物体光追材质节点::C_取物体光追材质节点(S_设备环境& ctx) : C_节点基类(DEF_取物体光追材质节点) {
	m_Name = L"取光追材质";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(L"物体");
	DEF_创建I8_1D插座_I(L"槽");

	DEF_创建板载缓存_1D插座_O(L"材质");
}

C_取物体光追材质节点::~C_取物体光追材质节点() {

}

bool C_取物体光追材质节点::f_update() {
	auto& obs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto& ms = *DEF_板载缓存插座_1D数据(f_get输出插座(1), 0);

	uint32 num = obs.size();
	if (!num) {
		ms.clear();
		return false;
	}

	if (num > 1) {
		ms.resize(num);
		auto obPtr = obs.data();
		auto mPtr = ms.data();
		for (uint32 i = 0; i < num; ++i) {
			auto& 链接材质 = f_ob_fromMesh(obs[0])->m_光追材质链接;
			for (auto& e : 链接材质) ms.emplace_back(e);
		}
	}
	else {
		ms.resize(num);
		auto& 链接材质 = f_ob_fromMesh(obs[0])->m_光追材质链接;
		ms.assign(链接材质.begin(), 链接材质.end());
	}

	return false;
}

C_节点基类* f_node_加载取物体光追材质节点(S_设备环境& ctx, FILE* f) {
	C_取物体光追材质节点* node = new C_取物体光追材质节点(ctx);
	return node;
}

void f_node_保存取物体光追材质节点(C_节点基类* n, FILE* f) {
	C_取物体光追材质节点* node = dynamic_cast<C_取物体光追材质节点*>(n);
}




C_选择物体节点::C_选择物体节点(S_设备环境 & ctx) : C_节点基类(DEF_选择物体节点){
	m_Name = L"选择物体";
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_O(L"物体");

	m_物体列表 = f_alloc_PropArrayContainer((S_Array*)(f_get输出插座(1)->f_getData(0)), L"物体列表", E_值类型::e_Type_Object_1D);
	//m_物体列表 = f_alloc_物体属性((S_OBArray*)f_get输出插座(1)->f_getData(0), L"物体列表");
	m_物体列表.m_私有 = true;
}

C_选择物体节点::~C_选择物体节点() {
	f_prop_Release(m_物体列表);
}

bool C_选择物体节点::f_update() {
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	//S_OBArray* 拾取的物体 = (S_OBArray*)f_prop_ArrayContainer(m_物体列表);
	//
	if (m_物体名称.size()) {
		//f_core_array_resize((S_Array*)obs, m_物体名称.size());
		f_core_array_clear((S_Array*)obs);

		for (auto& e : m_物体名称) {
			auto* ob = f_node_从全局物体容器查找物体(e);
			if (ob) {
				f_core_array_push_back((S_Array*)obs, (uint8*)&ob);
			}
		}

		if (obs->count == m_物体名称.size()) {
			m_物体名称.clear();
		}
	}
	
	
	for (uint32 i = 0; i < obs->count; ++i) {
		m_物体名称.push_back(obs->ptr_userData[i]->m_Name);

		if (m_显示数据) {
			obs->ptr_userData[i]->m_渲染 = true;
		}
		else {
			obs->ptr_userData[i]->m_渲染 = false;
		}
	}

	return false;
}

void C_选择物体节点::f_Show(bool open) {
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	for (uint32 i = 0; i < obs->count; ++i) {
		obs->ptr_userData[i]->m_渲染 = open;
	}
}

void C_选择物体节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);
	//f_prop_Load(m_物体列表, f);
	m_物体名称.clear();
	uint32 num = 0;
	fread(&(num), sizeof(uint32), 1, f);
	for (uint32 i = 0; i < num; ++i) {
		m_物体名称.push_back(f_file_读取字符串(f));
	}
}

void C_选择物体节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	//f_prop_Save(m_物体列表, f);
	S_OBArray* 拾取的物体 = (S_OBArray*)f_prop_ArrayContainer(m_物体列表);
	fwrite(&(拾取的物体->count), sizeof(uint32), 1, f);
	for (uint32 i = 0; i < 拾取的物体->count; ++i) {
		f_file_保存字符串(f, 拾取的物体->ptr_userData[i]->m_Name);
	}
}

C_节点基类* f_node_创建选择物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_选择物体节点(ctx);
}

C_节点基类* f_node_加载选择物体节点(S_设备环境& ctx, FILE* f) {
	C_选择物体节点* node = new C_选择物体节点(ctx);
	return node;
}
void		f_node_保存选择物体节点(C_节点基类* n, FILE* f) {
	C_选择物体节点* node = dynamic_cast<C_选择物体节点*>(n);
}




C_多边形物体节点::C_多边形物体节点(S_设备环境& ctx) : C_节点基类(DEF_多边形物体节点, E_节点类型::e_节点Type_物体) {
	
}

C_多边形物体节点::~C_多边形物体节点() {
	
}

bool C_多边形物体节点::f_update() {
	
	return false;
}

C_节点基类* f_node_创建多边形物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_多边形物体节点(ctx);
}

C_节点基类* f_node_加载多边形物体节点(S_设备环境& ctx, FILE* f) {
	C_多边形物体节点* node = new C_多边形物体节点(ctx);
	return node;
}

void        f_node_保存多边形物体节点(C_节点基类* n, FILE* f) {
	C_多边形物体节点* node = dynamic_cast<C_多边形物体节点*>(n);
}




C_目标摄像机节点::C_目标摄像机节点(S_设备环境& ctx) : C_节点基类(DEF_目标摄像机节点, E_节点类型::e_节点Type_物体) {
	m_Name = L"摄像机";
	m_Ctx = ctx;
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	m_Ob = f_node_创建虚拟体网格物体(ctx, E_物体类型::t_虚拟体);
	m_Ob->m_Name = L"摄像机虚拟体";

	auto* 目标物体 = f_node_创建虚拟体网格物体(ctx, E_物体类型::t_虚拟体);
	目标物体->m_Name = L"摄像机目标虚拟体";

	m_摄像机 = (S_摄像机*)f_ob_创建物体(m_Ctx, E_物体类型::t_摄像机);
	m_摄像机->m_Name = L"摄像机";
	f_ob_add子物体(m_Ob, m_摄像机);


	f_node_物体加入全局容器中(m_摄像机);
	f_node_物体加入全局容器中(m_Ob);
	f_node_物体加入全局容器中(目标物体);

	f_NodeCtx_录物体类节点(this);
	f_NodeCtx_录物体类节点(this, 目标物体);
	f_NodeCtx_录物体类节点(this, m_摄像机);


	C_插座基类* socket;
	DEF_创建物体插座_I(L"目标");
	DEF_创建F32插座_I(L"视野角度", &m_摄像机->m_视角);
	

	DEF_创建物体插座_O(L"摄像机");

	f_get输入插座(1)->f_setData(目标物体);
	f_get输出插座(1)->f_setData(m_Ob);

	m_Ob->f_set位置({1,1,1});
}

C_目标摄像机节点::~C_目标摄像机节点() {
}

bool C_目标摄像机节点::f_update() {
	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);
	
	目标物体->f_set旋转({});


	float32 视野角度 = DEF_F32插座数据(f_get输入插座(2));

	vec3 目标位置 = f_ob_get全局坐标(目标物体, 目标物体->m_实例ID);
	vec3 相机位置 = f_ob_get全局坐标(相机物体, 相机物体->m_实例ID);
	

	vec2 比例 = { float32(m_摄像机->m_分辨率.x), float32(m_摄像机->m_分辨率.y) };
	m_摄像机->f_set宽高比(比例);
	m_摄像机->f_set视角(视野角度);

	vec3 方向 = 相机位置 - 目标位置;
	f_node_设置摄像机虚拟网格(相机物体, m_摄像机);
	f_node_设置链接线方体虚拟网格(目标物体, {0.1f, 0.1f, 0.1f}, 方向);


	m_摄像机->m_视点距离 = -vec_normalize(&方向);
	m_摄像机->m_视点 = vec_反向(目标位置);
	m_摄像机->m_眼睛偏移 = {};

	vec4 quatX = f_graph_quat两向量(vec_normalize({ 方向.x, 0, 方向.z }), 方向);
	vec4 quatY = f_graph_quat两向量({0, 0, -1}, vec_normalize({ 方向.x, 0, 方向.z }));

	vec4 quat = f_graph_quat相乘(quatX, quatY);
	vec3 旋转 = f_graph_四元数转欧拉角(quat);
	相机物体->f_set旋转(旋转);


	
	//std::cout << "旋转.y = " << 旋转.y << std::endl;
	if (旋转.x < 0) {
		旋转.y = sign(旋转.y) * 180 - 旋转.y;
	}
	旋转.x = M_弧度转角度(f_graph_两向量夹角弧度(vec_normalize({ 方向.x, 0, 方向.z }), 方向));
	旋转.y *= sign(方向.y);

	if (方向.y < 0) {
		旋转.x = -旋转.x;
		旋转.y += 180;
	}
	旋转.x = -旋转.x;
	
	m_摄像机->f_set旋转({ 旋转.x, 旋转.y, 旋转.z });
	//std::cout<<"旋转.x = "<< 旋转.x << " " << std::endl;
	return false;
}

S_物体* C_目标摄像机节点::f_get虚拟体() {
	
	return m_Ob;
}

void C_目标摄像机节点::f_入回收() {
	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	f_node_移除虚拟体(m_Ob);
	f_node_移除虚拟体(目标物体);
}

void C_目标摄像机节点::f_回收() {
	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);

	vec3 目标位置 = f_ob_get全局坐标(目标物体, 目标物体->m_实例ID);
	vec3 相机位置 = f_ob_get全局坐标(相机物体, 相机物体->m_实例ID);

	vec3 方向 = 相机位置 - 目标位置;
	f_node_设置摄像机虚拟网格(相机物体, m_摄像机);
	f_node_设置链接线方体虚拟网格(目标物体, { 0.1f, 0.1f, 0.1f }, 方向);

}

void C_目标摄像机节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
		auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
		auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);
		下一次读取数据指针 = f_ob_Load物体(目标物体, 下一次读取数据指针);
		下一次读取数据指针 = f_ob_Load物体(相机物体, 下一次读取数据指针);
	}

	free(文件块.m_data);

}

void C_目标摄像机节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_file_构建文件块信息(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_节点数据::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);
	f_ob_Save物体(目标物体, 块);
	f_ob_Save物体(相机物体, 块);


	文件块.m_data = 块->ptr_userData;
	文件块.m_字节数 = 块->count;
	f_file_保存文件块(f, 文件块);

	f_core_array_free((S_Array*)块);
}

C_节点基类* f_node_创建目标摄像机节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_目标摄像机节点(ctx);
}
C_节点基类* f_node_加载目标摄像机节点(S_设备环境& ctx, FILE* f) {
	C_目标摄像机节点* node = new C_目标摄像机节点(ctx);
	return node;
}
void f_node_保存目标摄像机节点(C_节点基类* n, FILE* f) {
	C_目标摄像机节点* node = dynamic_cast<C_目标摄像机节点*>(n);
}













